package com.china.produce.aspect;

import com.china.produce.annotation.RateLimiter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


/**
 * 限流处理
 *
 * @ClassName
 * @Author niujie
 * @Version
 * @Description
 * @CreateTime 2023/3/23
 */
@Aspect
@Component
@Order(-3)
public class RateLimiterAspect {

    private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);

    @Autowired
    private RedisScript<Long> limitScript;


    @Autowired
    @Qualifier("redisTemplate2")
    private RedisTemplate<String, Object> redisTemplate;

    @Around("@annotation(rateLimiter)")
    public Object doAround(ProceedingJoinPoint joinPoint, RateLimiter rateLimiter) throws Throwable {
        int count = rateLimiter.count();
        int time = rateLimiter.time();
        String combineKey = getCombineKey(rateLimiter, joinPoint);
        List<String> keys = Collections.singletonList(combineKey);
        try {
            Long number = redisTemplate.execute(limitScript, keys, count, time);
            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
            if (Objects.isNull(number) || number.intValue() > count) {

                throw new RuntimeException("访问过于频繁，请稍候再试");
            } else {
               return joinPoint.proceed();
            }
        }  catch (Exception e) {
            throw new RuntimeException("服务器限流异常，请稍候再试" + e.getMessage());
        }
    }

    /**
     * 获取combineKey
     *
     * @param rateLimiter
     * @param point
     * @return
     */
    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {

        StringBuffer key = new StringBuffer(rateLimiter.key());

        MethodSignature signature = (MethodSignature) point.getSignature();

        Method method = signature.getMethod();

        Class<?> targetClass = method.getDeclaringClass();

        key.append(targetClass.getName()).append("-").append(method.getName());

        return key.toString();
    }

}
